package world.ztomorrow.push.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import world.ztomorrow.common.dto.RestResp;
import world.ztomorrow.push.client.NovelClient;
import world.ztomorrow.push.dao.mapper.FriendLinkMapper;
import world.ztomorrow.push.dao.mapper.HomeBookMapper;
import world.ztomorrow.push.dao.po.BookInfo;
import world.ztomorrow.push.dao.po.HomeBook;
import world.ztomorrow.push.dao.po.HomeFriendLink;
import world.ztomorrow.push.dto.resp.BookRankRespDto;
import world.ztomorrow.push.dto.resp.HomeBookRespDto;
import world.ztomorrow.push.dto.resp.HomeFriendLinkRespDto;
import world.ztomorrow.push.service.HomeService;
import world.ztomorrow.push.utils.CacheUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static world.ztomorrow.push.constant.PushConstant.*;


@Service
@RequiredArgsConstructor
public class HomeServiceImpl implements HomeService {

    private final CacheUtils cacheUtils;
    private final HomeBookMapper homeBookMapper;
    private final NovelClient novelClient;
    private final FriendLinkMapper friendLinkMapper;

    @Override
    public List<HomeBookRespDto> listHomeBooks() {
        List<HomeBookRespDto> cache = cacheUtils.getCache(
                obj -> BeanUtil.copyProperties(obj, HomeBookRespDto.class),
                CAFFEINE_HOME_BOOK, REDIS_HOME_BOOK,
                jsonStr -> JSONUtil.toBean(jsonStr, HomeBookRespDto.class));
        if (cache != null) return cache;
        // 未命中，从数据库查询
        List<HomeBook> list = new LambdaQueryChainWrapper<>(homeBookMapper)
                .orderByAsc(HomeBook::getSort)
                .list();
        // 健壮性判断
        if (list.isEmpty()) {
            return Collections.emptyList();
        }
        // 返回数据，并保存缓存
        List<BookInfo> bookInfos = novelClient.listHomeBooks(
                list.stream().map(HomeBook::getBookId).toList());
        Map<Long, BookInfo> bookInfoMap = bookInfos.stream()
                .collect(Collectors.toMap(BookInfo::getId, Function.identity()));
        List<HomeBookRespDto> homeBookRespDtOs = BeanUtil.copyToList(list, HomeBookRespDto.class);
        homeBookRespDtOs.forEach(v -> {
            BookInfo bookInfo = bookInfoMap.get(v.getBookId());
            v.setBookName(bookInfo.getBookName());
            v.setPicUrl(bookInfo.getPicUrl());
            v.setAuthorName(bookInfo.getAuthorName());
            v.setBookDesc(bookInfo.getBookDesc());
        });
        cacheUtils.saveCache(homeBookRespDtOs,
                CAFFEINE_HOME_BOOK, REDIS_HOME_BOOK, REDIS_HOME_BOOK_TTL,
                JSONUtil::toJsonStr);
        return homeBookRespDtOs;
    }

    @Override
    public List<HomeFriendLinkRespDto> listHomeFriendLinks() {
        List<HomeFriendLinkRespDto> cache = cacheUtils.getCache(
                obj -> BeanUtil.copyProperties(obj, HomeFriendLinkRespDto.class),
                CAFFEINE_HOME_FRIEND_LINK, REDIS_HOME_FRIEND_LINK,
                jsonStr -> JSONUtil.toBean(jsonStr, HomeFriendLinkRespDto.class));
        if (cache != null) return cache;
        // 从友情链接表中查询出友情链接列表
        List<HomeFriendLinkRespDto> list = new LambdaQueryChainWrapper<>(friendLinkMapper)
                .orderByAsc(HomeFriendLink::getSort)
                .list()
                .stream()
                .map(v -> {
                    HomeFriendLinkRespDto respDto = new HomeFriendLinkRespDto();
                    respDto.setLinkName(v.getLinkName());
                    respDto.setLinkUrl(v.getLinkUrl());
                    return respDto;
                }).toList();
        cacheUtils.saveCache(list,
                CAFFEINE_HOME_FRIEND_LINK, REDIS_HOME_FRIEND_LINK, REDIS_FRIEND_LINK_TTL,
                JSONUtil::toJsonStr);
        return list;
    }

    @Override
    public RestResp<List<BookRankRespDto>> listVisitRankBooks() {
        return RestResp.ok(listRankBooks(
                CAFFEINE_VISIT_RANK, REDIS_VISIT_RANK,
                REDIS_VISIT_RANK_TTL,BOOK_VISIT_COUNT ));
    }

    @Override
    public RestResp<List<BookRankRespDto>> listNewestRankBooks() {
        return RestResp.ok(listRankBooks(
                CAFFEINE_NEWEST_RANK, REDIS_NEWEST_RANK,
                REDIS_NEWEST_RANK_TTL,BOOK_CREATE_TIME ));
    }

    @Override
    public RestResp<List<BookRankRespDto>> listUpdateRankBooks() {
        return RestResp.ok(listRankBooks(
                CAFFEINE_UPDATE_RANK, REDIS_UPDATE_RANK,
                REDIS_UPDATE_RANK_TTL,BOOK_UPDATE_TIME ));
    }

    private List<BookRankRespDto> listRankBooks(String caffeineKey, String redisKey,
                                                long redisTTL, String orderKey) {
        List<BookRankRespDto> cache = cacheUtils.getCache(
                obj -> BeanUtil.copyProperties(obj, BookRankRespDto.class),
                caffeineKey, redisKey,
                jsonStr -> JSONUtil.toBean(jsonStr, BookRankRespDto.class));
        if (cache != null) return cache;

        List<BookRankRespDto> list = BeanUtil.copyToList(
                novelClient.listRankBooks(orderKey),
                BookRankRespDto.class);

        cacheUtils.saveCache(list, caffeineKey,
                redisKey, redisTTL, JSONUtil::toJsonStr);
        return list;
    }
}
